package com.joymart.admin.rest;

import com.joymart.common.model.Range;
import com.joymart.common.system.BusinessConfig;
import com.joymart.common.utils.DatetimeUtils;
import com.joymart.common.utils.ExcelExporter;
import com.joymart.common.utils.SecurityUtils;
import com.joymart.compute.model.OrderGain;
import com.joymart.dictionary.Dictionary;
import com.joymart.dictionary.DictionaryService;
import com.joymart.order.model.Order;
import com.joymart.order.service.OrderQueryService;
import com.joymart.recipient.service.CityService;
import com.joymart.user.service.UserService;
import lombok.Data;
import lombok.SneakyThrows;
import org.apache.poi.sl.draw.geom.GuideIf;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.math.MathContext;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;


@RestController
@RequestMapping("/admin")
public class OrderReportAdminController {

    @Autowired
    private UserService userService;
    @Autowired
    private CityService cityService;
    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    @Autowired
    private DictionaryService dictionaryService;
    @Autowired
    private OrderQueryService orderQueryService;
    @Autowired
    private BusinessConfig businessConfig;

    @GetMapping("/orders/base/export")
    public ResponseEntity<byte[]> exportBase(
            LocalDateTime start,
            LocalDateTime end,
            @RequestParam(value = "orderId", defaultValue = "") String orderId,
            @RequestParam(value = "receiver", defaultValue = "") String receiver,
            @RequestParam(value = "status", defaultValue = "") String category
    ) {
        SecurityUtils.requiresRestAuthority("OperatingDataView");
        Range range = Range.of(start, end);
        DatetimeUtils.checkRangeWithin(90, range);

        List<OrderQueryService.OrderAdminDTO> content;
        if (StringUtils.hasText(category) && !category.equals("null")) {
            content = orderQueryService.searchAdminOrders(range, orderId, receiver, PageRequest.of(0, 100_000),
                    Order.Status.valueOf(category)).getContent();

        } else {
            content = orderQueryService.searchAdminOrders(range, orderId, receiver, PageRequest.of(0, 100_000)).getContent();
        }
        return this.downloadBaseExcel(content);
    }


    @GetMapping("/orders/product/export")
    public ResponseEntity<byte[]> exportProduct(
            LocalDateTime start,
            LocalDateTime end,
            @RequestParam(value = "orderId", defaultValue = "") String orderId,
            @RequestParam(value = "receiver", defaultValue = "") String receiver,
            @RequestParam(value = "status", defaultValue = "") String category
    ) {
        SecurityUtils.requiresRestAuthority("OperatingDataView");
        Range range = Range.of(start, end);
        DatetimeUtils.checkRangeWithin(90, range);

        List<OrderQueryService.OrderAdminDTO> content;
        if (StringUtils.hasText(category) && !category.equals("null")) {
            content = orderQueryService.searchAdminOrders(range, orderId, receiver, PageRequest.of(0, 100_000),
                    Order.Status.valueOf(category)).getContent();

        } else {
            content = orderQueryService.searchAdminOrders(range, orderId, receiver, PageRequest.of(0, 100_000)).getContent();
        }
        return this.downloadProductExcel(content);
    }

    /**
     * 平台全量数据
     *
     * @param start
     * @param end
     * @return
     */
    @GetMapping("/orders/global/stats")
    public Object globalStats(LocalDateTime start,
                              LocalDateTime end) {

        SecurityUtils.requiresRestAuthority("OperatingDataView");
        String sql = " select count(*) as \"orderCount\",sum(total_price) as \"totalPrice\", sum(total_pv) as \"totalPv\" from \"order\" " +
                "where status = 'RECEIVED' and created_at between :start and :end ";

        return namedParameterJdbcTemplate.queryForMap(sql, Map.of("start", start, "end", end));
    }

    /**
     * 合营随单收益统计
     *
     * @param start
     * @return
     */
    @GetMapping("/orders/manager/gain")
    public Object managerGain(LocalDateTime start, LocalDateTime end) {
        SecurityUtils.requiresRestAuthority("OperatingDataView");
        String sql = "select owner_id, type, count(*) as \"orderCount\", sum(amount) as amount from \"order_gain\" " +
                " where created_at between :start and :end " +
                "   and type in('AU_DIRECTOR_GAIN','AG_DIRECTOR_GAIN','MANAGER_GAIN'" +
                ") " +
                " group by owner_id, type" +
                " order by owner_id, type ";

        List<ManagerGain> gains = namedParameterJdbcTemplate
                .query(sql, Map.of("start", start, "end", end),
                        new BeanPropertyRowMapper<>(ManagerGain.class));

        gains.forEach(gain -> gain.setAmountAsCash(gain.getAmount()
                .multiply(businessConfig.getPvCashRate(),
                        MathContext.DECIMAL64)));
        return gains;
    }

    @SneakyThrows
    private ResponseEntity<byte[]> downloadBaseExcel(List<OrderQueryService.OrderAdminDTO> dtos) {

        Dictionary productCategoryDict = dictionaryService.findByName("product_category");

        ExcelExporter<OrderQueryService.OrderAdminDTO> orderDTOExcelExporter = new ExcelExporter<>() {
            @Override
            protected String getSheetName() {
                return "订单基础";
            }

            @Override
            protected List<String> getHeaders() {
                return List.of("单号",
                        "（姓名）买家",
                        "品类",
                        "品名",
                        "单价",
                        "单品积分",
                        "数量",
                        "总额",
                        "积分",
                        "经营店铺",
                        "经营店铺手机号",
                        "经营利润",
                        "管理店铺",
                        "管理店铺手机号",
                        "育成利润",
                        "总部应收款",
                        "下单时间",
                        "运单号",
                        "收货省份",
                        "收货城市",
                        "收货地区",
                        "收货人地址          ",
                        "收货人姓名",
                        "收货人电话",
                        "买家备注",
                        "备注");
            }

        };

        Function<OrderQueryService.OrderAdminDTO, List<Object>> rowMapper = dto -> Arrays.asList(
                dto.getId(),
                dto.getBuyer().getNickname(),
                productCategoryDict.getItemText(dto.getProductMeta().optString("category")),
                dto.getProductName(),
                dto.getUnitPrice(),
                dto.getUnitPv(),
                dto.getQuantity(),
                dto.getTotalPrice(),
                dto.getTotalPv(),
                dto.getFirstSeller().getNickname(),
                dto.getFirstSeller().getMobile(),
                dto.getFirstSellerProfit(),
                dto.getSecondSeller().getNickname(),
                dto.getSecondSeller().getMobile(),
                dto.getSecondSellerProfit(),
                dto.getHeadQuarterPrice(),
                dto.getCreatedAt(),
                dto.getDeliveryNo(),
                Optional.ofNullable(dto.getReceiverDistrict())
                        .filter(StringUtils::hasText)
                        .map(cityService::parseProvince)
                        .orElse(""),
                Optional.ofNullable(dto.getReceiverDistrict())
                        .filter(StringUtils::hasText)
                        .map(cityService::parse)
                        .orElse(""),
                Optional.ofNullable(dto.getReceiverDistrict()).orElse(""),
                Optional.ofNullable(dto.getReceiverAddress()).orElse(""),
                Optional.ofNullable(dto.getReceiverName()).orElse(""),
                Optional.ofNullable(dto.getReceiverPhone()).orElse(""),
                Optional.ofNullable(dto.getRemark()).orElse(""),
                ""
        );

        byte[] content = orderDTOExcelExporter.exportToExcel(dtos, rowMapper);
        String fileName = "order-base.xlsx";
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
        headers.add(HttpHeaders.CONTENT_TYPE, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");


        return new ResponseEntity<>(content, headers, HttpStatus.OK);
    }

    @SneakyThrows
    private ResponseEntity<byte[]> downloadProductExcel(List<OrderQueryService.OrderAdminDTO> dtos) {

        Dictionary productCategoryDict = dictionaryService.findByName("product_category");

        ExcelExporter<OrderQueryService.OrderAdminDTO> orderDTOExcelExporter = new ExcelExporter<>() {
            @Override
            protected String getSheetName() {
                return "商品明细";
            }

            @Override
            protected List<String> getHeaders() {
                return List.of("品类", "品名", "数量", "时间", "收货城市", "备注");
            }

        };

        Function<OrderQueryService.OrderAdminDTO, List<Object>> rowMapper = dto -> Arrays.asList(
                productCategoryDict.getItemText(dto.getProductMeta().optString("category")),
                dto.getProductName(),
                dto.getQuantity(),
                dto.getCreatedAt(),
                Optional.ofNullable(dto.getReceiverDistrict())
                        .filter(StringUtils::hasText)
                        .map(cityService::parse)
                        .orElse(""),
                ""
        );

        byte[] content = orderDTOExcelExporter.exportToExcel(dtos, rowMapper);
        String fileName = "product-order.xlsx";
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + fileName);
        headers.add(HttpHeaders.CONTENT_TYPE, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");


        return new ResponseEntity<>(content, headers, HttpStatus.OK);
    }


    @Data
    private static class ManagerGain {
        private String type;
        private int orderCount;
        private BigDecimal amount;
        private BigDecimal amountAsCash;
        private String ownerId;

        public String getTypeText() {
            return Optional.ofNullable(OrderGain.Type.valueOf(this.type))
                    .map(OrderGain.Type::getText)
                    .orElse("");
        }
    }
}
